﻿using ZR.Model;
using ZR.Model.Souvenir;
using ZR.Model.Souvenir.Dto;
using ZR.Service.Souvenir.IService;
using ZR.ServiceCore.Model;

namespace ZR.Service.Souvenir
{
    [AppService(ServiceType = typeof(ICartService), ServiceLifetime = LifeTime.Transient)]
    public class CartService : BaseService<Cart>, ICartService
    {
        private readonly IProductService _productService;

        public CartService(IProductService productService)
        {
            _productService = productService;
        }

        public async Task<int> InsertCartAsync(Cart cart)
        {
            try
            {
                await Context.Ado.BeginTranAsync();
                var cartExisted = await Queryable()
                    .Where(c => c.ProductId == cart.ProductId && c.UserId == cart.UserId)
                    .FirstAsync();
                var res = 0;
                if (cartExisted != null)
                {
                    cartExisted.Quantity += cart.Quantity;
                    await UpdateCartAsync(cartExisted);
                }
                else
                {
                    res = await Insertable(cart).ExecuteCommandAsync();
                }
                var product = await _productService.SelectProductAsyncById(cart.ProductId);
                product.Stock -= cart.Quantity;
                await _productService.UpdateProductAsync(product);
                await Context.Ado.CommitTranAsync();
                return res;
            }
            catch (Exception e)
            {
                await Context.Ado.RollbackTranAsync();
                throw;
            }
        }

        public async Task<int> UpdateCartAsync(Cart cart)
        {
            return await Updateable(cart).ExecuteCommandAsync();
        }

        public async Task<int> DeleteCartAsync(int cartId)
        {
            try
            {
                await Context.Ado.BeginTranAsync();
                var cart = await SelectCartAsyncById(cartId);
                if (cart == null) throw new Exception("要删除的购物车不存在");
                var product = await _productService.SelectProductAsyncById(cart.ProductId);
                product.Stock += cart.Quantity;
                await _productService.UpdateProductAsync(product);
                var res = await Deleteable()
                    .Where(it => it.Id == cartId)
                    .ExecuteCommandAsync();
                await Context.Ado.CommitTranAsync();
                return res;
            }
            catch (Exception e)
            {
                await Context.Ado.RollbackTranAsync();
                throw;
            }
        }

        public async Task<PagedInfo<CartDto>> SelectCartWithPageAsync(CartQueryDto cartQueryDto)
        {
            RefAsync<int> total = 0;
            var exp = Expressionable.Create<Cart>();
            exp.And(c => c.UserId == cartQueryDto.UserId);
            var res = await Queryable()
                .LeftJoin<Product>((c, p) => c.ProductId == p.Id)
                .LeftJoin<SysFile>((c,p, f) => p.ImageId == f.Id)
                .LeftJoin<Category>((c,p, f, ca) => p.CategoryId == ca.Id)
                .Where(exp.ToExpression())
                .Select((c,p, f, ca) => new CartDto()
                {
                    Id = c.Id,
                    ProductId = c.ProductId,
                    Name = p.Name,
                    ImageId = p.ImageId,
                    ImageUrl = f.AccessUrl,
                    Price = p.Price,
                    Stock = p.Stock,
                    Quantity = c.Quantity,
                    Detail = p.Detail,
                    CategoryId = p.CategoryId,
                    CategoryName = ca.Name,
                    UserId = c.UserId
                })
                .ToPageListAsync(cartQueryDto.PageNum, cartQueryDto.PageSize, total);
            var page = new PagedInfo<CartDto>()
            {
                PageIndex = cartQueryDto.PageNum,
                PageSize = cartQueryDto.PageSize,
                Result = res,
                TotalNum = total
            };
            return page;
        }

        public async Task<Cart> SelectCartAsyncById(int cartId)
        {
            return await Queryable()
                .Where(it => it.Id == cartId)
                .FirstAsync();
        }
    }
}